package xml;

import java.util.*;

//*****************************************************************************
//*** CLASS: XMLElement
//*****************************************************************************
// Definition: Each XML document contains one or more elements, the boundaries
// of which are delimited by start-tags and end-tags.
// Each element has a type, identified by name, and MAY have a set of attribute specifications.]
// Each attribute specification has a name and a value.
//
// http://www.w3.org/TR/2004/REC-xml-20040204/#sec-logical-struct
// http://www.w3.org/TR/xhtml1/
public class XMLElement
{ private static final int START=0;
  private static final int END=1;
  private static final int EMPTY=2;

  private XMLElement parent;
  private String name;
  private Hashtable attributes;
  private Vector content; // List of child elements and text strings

  // ***************************************************************************
  // *** CONSTRUCTOR: XMLElement
  // ***************************************************************************
  public XMLElement(XMLElement parent,String name,Hashtable attributes)
  { this.parent=parent;
    this.name=name;
    this.attributes=attributes;
  }

  
  // ***************************************************************************
  // *** PUBLIC METHODS
  // ***************************************************************************

  public XMLElement getParent() { return(parent); }
  public String getName() { return(name); }
//  public Enumeration getContent() { return(content.elements()); }
  public Vector getContent() { return(content); }
  public String getText() { return(getAllText().toString()); }

  public void addChild(XMLElement elt) { addContent(elt); }
  public void addText(String text) { addContent(text); }

  public void setAttribute(String name,String value)
  { if(name==null || value==null) return;
    if(attributes==null) attributes=new Hashtable();
    attributes.put(name,value);
  }

  public String getAttribute(String name)
  { if(attributes==null) return(null);
    String value=(String)attributes.get(name);
    if(value==null) return(null);
    if(value.length()==0) return(null);
    return(value);
  }
  
  public String getAttribute(String name,String defaultValue)
  { String value=getAttribute(name);
    if(value==null) return(defaultValue);
    return(value);
  }
  
  public int getAttributeInt(String name,int defaultValue)
  { try { return(Integer.parseInt(getAttribute(name))); }
    catch(IllegalArgumentException iae) {}
    catch(NullPointerException npe) {}
    return(defaultValue);
  }

  public Vector getChildren(String tagname)
  { if(content==null) return(null);
	Vector res=null;
	for(Enumeration e=content.elements();e.hasMoreElements();)
	{ Object obj=e.nextElement();
	  if(obj instanceof XMLElement)
	  { if(res==null) res=new Vector();
        if(((XMLElement)obj).getName().equals(tagname)) res.addElement(obj);
	  }
	}
	return(res);
  }

  public XMLElement getChild(String tagname)
  { if(content==null) return(null);
	for(Enumeration e=content.elements();e.hasMoreElements();)
	{ Object obj=e.nextElement();
	  if(obj instanceof XMLElement)
	  { if(((XMLElement)obj).getName().equals(tagname)) return((XMLElement)obj); }
	}
	return(null);
  }

  public String getChildText(String tagname)
  { XMLElement child=getChild(tagname);
    if(child!=null) return(child.getText());
    return("");
  }

  public String toXML()
  { StringBuffer buf=new StringBuffer();
	if(content!=null)
    { appendTag(buf,START);
      for(Enumeration e=content.elements();e.hasMoreElements();)
      { buf.append(e.nextElement().toString()); }
      appendTag(buf,END);
    } else appendTag(buf,EMPTY);
    return(buf.toString());
  }

  public String toXMLBody()
  { StringBuffer buf=new StringBuffer();
	if(content!=null)
    { //appendTag(buf,START);
      for(Enumeration e=content.elements();e.hasMoreElements();)
      { buf.append(e.nextElement().toString()); }
      //appendTag(buf,END);
    } //else appendTag(buf,EMPTY);
    return(buf.toString());
  }

  public String toString() { return(toXML()); }
  
  
  // *************************************************************************
  // *** PRIVATE PART
  // *************************************************************************

  private void addContent(Object obj)
  { if(content==null) content=new Vector();
    content.addElement(obj);
  }

  private StringBuffer getAllText()
  { if(content==null) return(null);
    StringBuffer allText=null;
	for(Enumeration e=content.elements();e.hasMoreElements();)
    { Object obj=e.nextElement();
      if(obj instanceof String)
      { if(allText==null) allText=new StringBuffer();
   	    allText.append((String)obj);
      }
    }
	return(allText);
  }

  private void appendAttributes(StringBuffer buf)
  { Enumeration e=attributes.keys();
    while(e.hasMoreElements())
    { String key=(String)e.nextElement();
      String value=(String)attributes.get(key);
      buf.append(' ');
      buf.append(key);
      buf.append("=\"");
      buf.append(value);
      buf.append('\"');
    }
  }
  
  private void appendTag(StringBuffer buf,int type)
  { buf.append('<');
    if(type==END) buf.append('/');
    buf.append(name);
    if(type!=END && attributes!=null) appendAttributes(buf);
    if(type==EMPTY) buf.append('/');
    buf.append('>');
  }


}